/*
 * texture.cpp
 *
 *  Created on: Oct 8, 2009
 *      Author: rcd
 */
#include <stdlib.h>
#include <unistd.h>      // for FILE
#include <stdio.h>       // for malloc
#include <jpeglib.h>     // for jpeg routines
#include "texture.h"



GLubyte* readJPG (const string& filename, GLuint& width, GLuint& height)
{
    FILE * infile;
    if (!(infile = fopen(filename.c_str(), "rb"))) return NULL;

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);
    if (cinfo.err->msg_code > 0)
    {
        jpeg_destroy_decompress(&cinfo);
        fclose(infile);
        return NULL;
    }

    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, infile);
    jpeg_read_header(&cinfo, TRUE);
    jpeg_start_decompress(&cinfo);

    GLint row_stride = cinfo.output_width * cinfo.output_components;
    JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) & cinfo,
                                                   JPOOL_IMAGE, row_stride, 1);
    JSAMPLE* data_buffer = (JSAMPLE*)malloc(cinfo.image_width
            * cinfo.image_height * cinfo.output_components);
    long cont = 0;
    while (cinfo.output_scanline < cinfo.output_height)
    {
        jpeg_read_scanlines(&cinfo, buffer, 1);
        memcpy(data_buffer + cinfo.image_width * cinfo.output_components * cont,
               buffer[0], row_stride);
        cont++;
    }
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);

    width = cinfo.image_width;
    height = cinfo.image_height;
    GLubyte* data = (GLubyte*)malloc(width * height * 3);
    switch (cinfo.output_components)
    {
        case 1:
            for (GLuint i = 0, j = 0; i < width * height; i += 1, j += 3)
            {
                data[j] = data[j + 1] = data[j + 2] = data_buffer[i];
            }
            break;
        case 3:
            for (GLuint i = 0, j = 0; i < width * height * 3; i += 3, j += 3)
            {
                data[j] = data_buffer[i];
                data[j + 1] = data_buffer[i + 1];
                data[j + 2] = data_buffer[i + 2];
            }
            break;
        default:
            free(data_buffer);
            return NULL;
    }
    free(data_buffer);
    return data;
}


// Determines type of image file and reads that specific format.
GLubyte* Texture::readFile (const string& filename, GLuint& width, GLuint& height)
{
    string suffix = filename.substr(filename.find_last_of("\\.")+1);
    if (suffix == "jpg")     return readJPG(filename, width, height);
    // else if ...
    else		     return 0;
}
